package com.xu.GOF23.single;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

public class reflectBreak3 {
    //当两个都是通过反射创建 解决办法通过创建一个私有的标志位来检测
    private static boolean xuTingOk = false;

    private reflectBreak3() {
        //当一个调用getInstance来通过构造器创建，一个通过反射创建 解决办法
        synchronized (reflectBreak3.class) {
            if (xuTingOk == false) {//通过标志位来检测 ，如果在不通过反编译的情况下，是找不到关键字的
                xuTingOk = true;
            } else {
                throw new RuntimeException("不要试图使用反射来破坏异常");
            }
        }
        System.out.println("当前线程" + Thread.currentThread().getName() + "进入构造器创建对象");
    }

    private volatile static reflectBreak3 LazyManDead;

    public static reflectBreak3 getInstance() {
        if (LazyManDead == null) {//隔离除了第一次调用以外的调用，提高效率
            synchronized (reflectBreak.class) {
                if (LazyManDead == null) {
                    LazyManDead = new reflectBreak3();
                }
            }
        }
        return LazyManDead;
    }

    public static void main(String[] args) throws Exception {
//        reflectBreakSolution2 lazyMan1= reflectBreakSolution2.getInstance();//通过调用方法创建一个 懒汉1
        //通过反射来破解防御的标志位
        Field xuTingBreak = reflectBreak3.class.getDeclaredField("xuTingOk");
        xuTingBreak.setAccessible(true);


        Constructor<reflectBreak3> declaredConstructor = reflectBreak3.class.getDeclaredConstructor(null);//传入null 即得到一个空参构造器
        declaredConstructor.setAccessible(true);
        //setAccessible(true)这个是为了强行获得构造器的访问权限，比如说单例模式的类的构造器是私有的，你需要通过反射实例一个对象，就必须要有这一句，否则会引发非法访问权限异常
        reflectBreak3 lazyMan = declaredConstructor.newInstance();

        //在反射创建了一个把字段改为true之后 我人为的又改回来false
        xuTingBreak.set(lazyMan, false);

        reflectBreak3 lazyMan1 = declaredConstructor.newInstance();
        System.out.println(lazyMan);
        System.out.println(lazyMan1);

    }
}
